#include "lwip/apps/tftp_server.h"
#include "mytftpserverif.h"
#include <string.h>
#include <stdio.h>
#include "main.h"
#include "MBapp.h"
#include "flash_if.h"
#include "stdlib.h"



//#define TEST_BUG   //2020-05-07
static char getfilename[TFTP_MAX_FILENAME_LEN];
static char readfilename[TFTP_MAX_FILENAME_LEN];
static uint32_t getfilelen = 0;
static uint16_t bilknum = 0;

__packed typedef struct 
{
  uint8_t   InitFlat;
  uint8_t   W_R_Mode;   //��дģʽ   1д  0��
  uint32_t  Flash_Addr ;
}Iap_FlashCont;


static  Iap_FlashCont   Iapflashcont ;



static void * OpenFile(const char* fname, const char* mode, u8_t write);
static void Close_File(void* handle);
static int Read_File(void* handle, void* buf, int bytes);
static int Write_File(void* handle, struct pbuf* p);

const struct tftp_context  tftpContext={       //TFTP SERVER �Խӽӿ�
 OpenFile,
 Close_File,
 Read_File,    
 Write_File,
};

/**********指定地址后生成文件最小128K   ".ARM.__at_0x801FF00"************/
#define DEV_CODE_ID   0XAA55AA00
#if (FLASH_BASE_OFFSET == SOFT_0X20000)
const  char devName[] __attribute__((at(USER_FLASH_SAVE_APP_ADDRESS+USER_FLASH_APP_DEV_ID))) = IAP_BIN_NAME;
#endif

/************************TFTP升级下发第一帧数据***********************/
static void * OpenFile(const char* fname, const char* mode, u8_t write)
{  
  
	Iapflashcont.W_R_Mode = write ;
	#ifdef TEST_BUG	
  printf("open file  %s \r\n",fname);    
  printf("open mode  %s \r\n",mode); 
  Iapflashcont.W_R_Mode ? printf("write file \r\n") : printf("read file \r\n");
	#endif
 
  if(Iapflashcont.W_R_Mode == 1)//write file 
  {
    FLASH_If_Init();   //enable
		getfilelen = 0;
		bilknum = 0;
    Iapflashcont.Flash_Addr = USER_FLASH_FIRST_PAGE_ADDRESS ;  //FLASH save file adder
		#ifdef TEST_BUG	
    printf("erase Flash   \r\n");  
		#endif
    if( FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS) == 0 )   //erase Flash
    {
      Iapflashcont.InitFlat =1 ;   //start write file 
			#ifdef TEST_BUG	
      printf("Write File Init Succes \r\n");
			#endif
    }
		memcpy(getfilename,fname,TFTP_MAX_FILENAME_LEN);//lwadd
  } //read file 
  else if(memcmp(fname,"flash.bin",strlen("flash.bin"))==0)  //read file name
  {
    Iapflashcont.InitFlat =1 ;   //start
		#ifdef TEST_BUG	
    printf("Read File Init Succes \r\n");
		#endif
    Iapflashcont.Flash_Addr = FLASH_BASE ;  //read FLASH 
  }
  return (Iapflashcont.InitFlat) ? (&Iapflashcont) : NULL ;  //
}

/************************TFTP升级故障或完成***********************/
static void Close_File(void* handle)
{
//	uint8_t num;
  Iap_FlashCont * Filehandle = (Iap_FlashCont *) handle ;
     
  
  Filehandle->InitFlat = 0 ;
	#ifdef TEST_BUG	
  printf("close file\r\n"); 
  #endif	
	
  if(Filehandle->W_R_Mode && (3 == closeflag))  //write file
  { 
		FLASH_If_Init();   //enable
		/* 为了兼容出厂程序是6160以前的程序升级 */
//		Filehandle->Flash_Addr = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_NAME_OFFSET;
//		if( FLASH_If_Write((__IO uint32_t*)&Filehandle->Flash_Addr,(uint32_t *)getfilename,TFTP_MAX_FILENAME_LEN/4) == 0 )
//		{
//			#ifdef TEST_BUG	
//			printf("Write FLASH  save file name 0X%08X \r\n",Filehandle->Flash_Addr);
//			#endif
//		}
		
		Filehandle->Flash_Addr = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_NAME_OFFSET + TFTP_MAX_FILENAME_LEN;
		if( FLASH_If_Write((__IO uint32_t*)&Filehandle->Flash_Addr,(uint32_t *)&getfilelen,1) == 0 )
		{
			#ifdef TEST_BUG	
			printf("Write FLASH  save file len = 0X%08X  0X%08X \r\n",getfilelen,Filehandle->Flash_Addr);
			#endif
		}
		getfilelen = 0;
		FLASH_If_UnInit();  //FLASH disable
		HAL_NVIC_SystemReset();
  }
	else if(Filehandle->W_R_Mode){
		getfilelen = 0;
		FLASH_If_UnInit();  //FLASH disable
		HAL_NVIC_SystemReset();	
	}
	FLASH_If_UnInit();  //FLASH disable
}


#define  SOFE_INIT_FLAG  0x55aaaa55
uint32_t i,len,u32FlashAddr,u32FlashAddrW,rvdata;
void sofe_reset(void)
{	
	uint16_t resetflag;
	GETRegHolding3(MB_SOFE_RESER, &resetflag, 1);
	if(tftperr)
	{
		HAL_NVIC_SystemReset();		
	}
	
	#if  (FLASH_BASE_OFFSET == SOFT_0X20000) 
	if(0xaa55 == resetflag){
		rvdata = SOFE_INIT_FLAG;
	  	FLASH_If_Init();   //enable
		u32FlashAddr = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_RESET_ADDR;	
	 	 if( FLASH_If_Write((__IO uint32_t*)&u32FlashAddr,(uint32_t *)&rvdata,1) == 0 )//恢复出厂版本标志
		{
			HAL_NVIC_SystemReset();			
		}
	} 
	#endif	
}

void Jump_To_AppReady(void)
{	
	#if (USE_IAP_TFTP==FUN_ENABLE)	
	uint8_t errFlag = 0;
	
	FLASH_If_Init();   //enable

	u32FlashAddr = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_DEV_ID;	
	for(i = 0; i < (TFTP_MAX_FILENAME_LEN / 4); i++){
		((uint32_t *)readfilename)[i] = (*(__IO uint32_t*)u32FlashAddr);
		u32FlashAddr +=4;
	}
	if(memcmp(readfilename,IAP_BIN_NAME,IAP_NAME_LEN) == 0){
		u32FlashAddr = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_NAME_OFFSET + TFTP_MAX_FILENAME_LEN;
	  	len = (*(__IO uint32_t*)u32FlashAddr);
	}
	else if(0xff != (uint8_t)readfilename[0] && 0xff != (uint8_t)readfilename[1] ){//file name err
		mbSofeStus = 3;
	}
	else{
		/* 判断是否有升级数据 */
		u32FlashAddr = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_NAME_OFFSET + TFTP_MAX_FILENAME_LEN;
	  	len = (*(__IO uint32_t*)u32FlashAddr);
		
		if(0XFFFFFFFF != len ){ /*有升级数据*/
			len = 0;
			mbSofeStus = 5;
		}
		else{                    /*无升级数据*/
			len = 0;
		}
	}	
	
	if(len){ //have updata file 
		FLASH_If_Erase(USER_FLASH_SAVE_APP_ADDRESS);
	  
		u32FlashAddr= USER_FLASH_FIRST_PAGE_ADDRESS;
		u32FlashAddrW = USER_FLASH_SAVE_APP_ADDRESS;
		for(i=0;i<len;i++){
			rvdata = (*(__IO uint32_t*)u32FlashAddr);	
			if( FLASH_If_Write((__IO uint32_t*)&u32FlashAddrW,(uint32_t *)&rvdata,1) != 0 )//false
			{
				errFlag++;
				break;
			}
			u32FlashAddr +=4;
		}
		#ifdef TEST_BUG	
		//printf("copy FLASH   %08X\r\n",len);
		#endif
		if(0 == errFlag){//copy data OK
			FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS);	
      		HAL_NVIC_SystemReset();			
		}
		else{  //copy data err
			mbSofeStus = 2;	
		}
	}
	else{
		u32FlashAddr = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_RESET_ADDR;	
		rvdata = (*(__IO uint32_t*)u32FlashAddr);
		if(SOFE_INIT_FLAG == rvdata){//reset factory
			FLASH_If_Erase(USER_FLASH_SAVE_APP_ADDRESS);
		}
	}
	
	if(mbSofeStus > 1)
	{
		FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS);
		rvdata = mbSofeStus;
		u32FlashAddrW = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_UPDATA_ERR;
		FLASH_If_Write((__IO uint32_t*)&u32FlashAddrW,(uint32_t *)&rvdata,1);	  
	}
	FLASH_If_UnInit();  //FLASH disable
	#endif
}
uint32_t regdata;
void Jump_To_App(void)
{
	#if (USE_IAP_TFTP==FUN_ENABLE)
  typedef  void (*pFunction)(void);
    pFunction Jump_To_Application;
    uint32_t JumpAddress;
    /* Check if valid stack address (RAM address) then jump to user application */
	regdata = (*(__IO uint32_t*)USER_FLASH_SAVE_APP_ADDRESS);
	#ifdef TEST_BUG	
	printf("Jump_To_App  %x\r\n",regdata);
	#endif
   	if (((*(__IO uint32_t*)USER_FLASH_SAVE_APP_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
   	{
		#ifdef TEST_BUG	
		printf("Jump_To_App\r\n");
		#endif
		/* Jump to user application */
		JumpAddress = *(__IO uint32_t*) (USER_FLASH_SAVE_APP_ADDRESS + 4);
		Jump_To_Application =   (pFunction)JumpAddress;
		/* Initialize user application's Stack Pointer */
		__set_MSP(*(__IO uint32_t*) USER_FLASH_SAVE_APP_ADDRESS);
		Jump_To_Application();
			
		/* do nothing */
		while(1);
   	}
	#endif
}

void IAP_Jump_Fun(void)
{
  #if  (FLASH_BASE_OFFSET == SOFT_0X00000)
	mbSofeStus = 0;
	Jump_To_AppReady();
	Jump_To_App();
	#else
	mbSofeStus = 1;
	u32FlashAddr = USER_FLASH_FIRST_PAGE_ADDRESS + USER_FLASH_APP_UPDATA_ERR;	
	rvdata = (*(__IO uint32_t*)u32FlashAddr);
	if(0XFFFFFFFF != rvdata)
	{
	  mbSofeStus = rvdata&0xFF;
	  mbSofeStus = (2 == mbSofeStus) ? 12 : 13;
  	}
	#endif
}
/************************TFTP读数据***********************/
static int Read_File(void* handle, void* buf, int bytes)
{  
  	Iap_FlashCont * Filehandle = (Iap_FlashCont *) handle ;
	#ifdef TEST_BUG	
  	printf("read data len  %d \r\n",bytes);    
	#endif
	if(!Filehandle->InitFlat)  //is start
	{
		return ERR_MEM ;
	} 
	uint16_t Count ;
	for(  Count = 0 ; (Count < bytes)&&(Filehandle->Flash_Addr<=FLASH_END)  ;  Count++ ,Filehandle->Flash_Addr++ )
	{
	((uint8_t *)buf)[Count] = *((__IO uint8_t *) Filehandle->Flash_Addr);  
	}
	return Count;
}


/************************TFTP下发文件数据***********************/
static int Write_File(void* handle, struct pbuf* p)
{
	
	uint16_t Count ;
	Iap_FlashCont * Filehandle = (Iap_FlashCont *) handle ;  
	#ifdef TEST_BUG		
	printf("write data len %d %d \r\n",p->len,bilknum); 
	#endif
	if(!Filehandle->InitFlat)
	{
			#ifdef TEST_BUG	
		printf("write file : donot init \r\n");
			#endif
		return ERR_MEM ;
	}

	if(bilknum != (writeBlknum-1)){//2020-05-07 网线断开，数据保存，但没应答，TFTP会再次发送这段数据
		#ifdef TEST_BUG	
		printf("write file : this bilk have save \r\n");
		#endif
		return ERR_OK ;
	}
	Count = p->len/4 +((p->len%4)>0);  //4byte
	#ifdef TEST_BUG	
	//printf("Write FLASH  adder start 0X%08X \r\n",Filehandle->Flash_Addr);
	#endif

	if( FLASH_If_Write((__IO uint32_t*)&Filehandle->Flash_Addr,(uint32_t *)p->payload,Count) == 0 )
	{
		getfilelen = getfilelen + Count;
		bilknum++;
		#ifdef TEST_BUG			
		printf("Write FLASH  adder over  0X%08X \r\n",Filehandle->Flash_Addr);
		#endif
		return ERR_OK;
	}
	else
	{
		#ifdef TEST_BUG	
		printf("Write FLASH false adder  0X%08X \r\n",Filehandle->Flash_Addr);
		#endif
	}
	return ERR_MEM;
}






